////////////////////////////////////////////////////////////////
// filename: camera.cpp
// description: handle all the camera events
// autor: Jay Tomten (jaytomten@gmail.com)
// notes:

// namespace

// defines

// includes
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#endif
#include <SDL/SDL.h>
#include <iostream>
#include "camera.h"
#include <math.h>

// globals

////////////////////////////////////////////////////////////////
// constructor
Camera::Camera()
    {

    // use Init()

    }

////////////////////////////////////////////////////////////////
// destructor
Camera::~Camera()
    {

    // nothing to delete

    }

////////////////////////////////////////////////////////////////
// Init() - set it up right!
bool Camera::Init()
    {

    cout << "Camera initialization... ";
    demo = false;
    story = false;

    // initially set to false, no movements
    in = false;
    out = false;
    left = false;
    right = false;

    // generic starting position
    pos.Init(0.0f, 0.0f, 20.0f);
    aim.Init(0.0f, 0.0f,  0.0f);
    top.Init(0.0f, 1.0f,  0.0f);
    vel.Init(1.0f, 1.0f, 20.0f);

    // the camera is limited to this area
    camLimitPos.Init( 100.0f, 0.0f, 70.0f);
    camLimitNeg.Init(-100.0f, 0.0f, 10.0f);
    cout << "success.\n";

    return true;

    }

////////////////////////////////////////////////////////////////
// Update() - set the camera where is suppose to be
bool Camera::Update(float d)
    {

    // scroll is demo active
    if(demo) pos.x = pos.x - vel.x * (d / 50.0f) * pos.z;
    if(story)
        {
        pos.z = 70.0f;
        pos.x = pos.x + vel.x * (d / 2.0f) * pos.z;
        }

    // process events
    if(in) pos.z = pos.z - vel.z * d;
    if(out) pos.z = pos.z + vel.z * d;
    if(left) pos.x = pos.x - vel.x * d * pos.z;
    if(right) pos.x = pos.x + vel.x * d * pos.z;

    // camera aim lag
    if(aim.x > pos.x)
        {
        aim.x = aim.x - (vel.x / 1.25) * d * pos.z;
        if(aim.x < pos.x) aim.x = pos.x;
        }
    if(aim.x < pos.x)
        {
        aim.x = aim.x = aim.x + (vel.x / 1.25) * d * pos.z;
        if(aim.x > pos.x) aim.x = pos.x;
        }

    // reset movement calls
    in = false;
    out = false;
    left = false;
    right = false;

    // check out limits
    if(pos.x > camLimitPos.x) pos.x = camLimitPos.x;
    if(pos.y > camLimitPos.y) pos.y = camLimitPos.y;
    if(pos.z > camLimitPos.z) pos.z = camLimitPos.z;
    if(pos.x < camLimitNeg.x) pos.x = camLimitNeg.x;
    if(pos.y < camLimitNeg.y) pos.y = camLimitNeg.y;
    if(pos.z < camLimitNeg.z) pos.z = camLimitNeg.z;

    // place the camera
    gluLookAt(pos.x, pos.y, pos.z,
              aim.x, aim.y, aim.z,
              top.x, top.y, top.z);
    return true; // always return true, useless

    }

////////////////////////////////////////////////////////////////
// In() - zoom in
void Camera::In()
    {

    in = true;

    }

////////////////////////////////////////////////////////////////
// Out() - zoom out
void Camera::Out()
    {

    out = true;

    }

////////////////////////////////////////////////////////////////
// Left() - move the camera left
void Camera::Left()
    {

    left = true;

    }

////////////////////////////////////////////////////////////////
// Right() - move the camera right
void Camera::Right()
    {

    right = true;

    }

////////////////////////////////////////////////////////////////
// GoTo() - go to a specified location
void Camera::GoTo(float x, float y, float z)
    {

    pos.Init(x, y, pos.z);
    aim.Init(x, y, z);
    top.Init(0.0f, 1.0f, 0.0f);

    }

////////////////////////////////////////////////////////////////
// DistanceTo() - distance from a specified location
float Camera::DistanceTo(float x, float y, float z)
    {
    return sqrt(((x - pos.x) * (x - pos.x)) + ((y - pos.y) * (y - pos.y)) + ((z - pos.z) * (z - pos.z)));
    }
